package com.lagou.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author tengfei wang
 * @version 1.0
 * @date Created in 2020/8/31
 */
public class BeanFactory {

    private static HashMap<String, Object> beanMap = new HashMap<>();

    static {
        try {
            //读取beans xml配置文件
            InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.xml");
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            //解析所有bean标签，并放入map中
            List<Element> beanList = rootElement.selectNodes("//bean");
            for (Element element : beanList) {
                String id = element.attributeValue("id");
                String className = element.attributeValue("class");
                Class<?> aClass = Class.forName(className);
                Object o = aClass.newInstance();
                beanMap.put(id, o);
            }

            //解析bean的依赖标签property，并通过set方法注入到对应的类中
            List<Element> properties = rootElement.selectNodes("//property");
            for (Element property : properties) {
                Element parent = property.getParent();
                String id = parent.attributeValue("id");
                Object parentObj = beanMap.get(id);
                Method[] methods = parentObj.getClass().getDeclaredMethods();
                //找到set方法，注入
                List<Method> methodList = Arrays.stream(methods).filter(w -> {
                    String methodName = "set" + property.attributeValue("name");
                    return w.getName().equalsIgnoreCase(methodName);
                }).collect(Collectors.toList());
                if (methodList.size() <= 0) {
                    throw new RuntimeException("依赖对象未找到");
                }
                String ref = property.attributeValue("ref");
                Object childObj = beanMap.get(ref);
                methodList.get(0).invoke(parentObj, childObj);
            }
        } catch (DocumentException | InstantiationException | IllegalAccessException | ClassNotFoundException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过bean name获取bean
     *
     * @param name bean name
     * @return bean对象
     */
    public static Object getBean(String name) {
        return beanMap.get(name);
    }

    public static void main(String[] args) {
        System.out.println(BeanFactory.beanMap);
    }

}
